package com.xyy.saas.payment.adpater.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xyy.saas.payment.adpater.PaymentAdapter;
import com.xyy.saas.payment.adpater.jd.common.JDConstants;
import com.xyy.saas.payment.adpater.jd.service.JDAdpaterService;
import com.xyy.saas.payment.adpater.jd.vo.*;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.*;
import com.xyy.saas.payment.cores.enums.JDPayTradeStatusEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.param.TransactionParam;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.PrePayOrder;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.merchant.core.dto.QueryTransactionStatusDto;
import com.xyy.saas.payment.payment.core.bo.RefundBO;
import com.xyy.saas.payment.payment.core.dto.OrderClosedDto;
import com.xyy.saas.payment.payment.core.dto.PayDto;
import com.xyy.saas.payment.payment.core.dto.PrepayDto;
import com.xyy.saas.payment.payment.core.dto.RefundDto;
import com.xyy.saas.payment.payment.core.service.PrePayOrderService;
import com.xyy.saas.payment.service.PayResultOrderService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * 京东支付
 */
@Service
@Slf4j
public class JDAdapter implements PaymentAdapter {
    @Autowired
    private JDAdpaterService jdAdpaterService;
    @Autowired
    private PrePayOrderService prePayOrderService;
    @Autowired
    private PayResultOrderService payResultOrderService;

    /**
     * 创建预支付单
     */
    @Override
    public PrepayBo prepay(PrepayDto prepayDto) throws PaymentException {
        log.info("JDAdapter#prepay payDto={}", JSONUtils.toJSON(prepayDto));
        return prePayOrderService.prepayOrderByPrepayDto(prepayDto);
    }

    /**
     * 支付
     */
    @Override
    public PayBo pay(PayDto payDto) throws PaymentException {
        String logPrefix = "jdCardPay " + payDto.getPayNo();
        log.info("{} JDAdapter#pay payDto={}", logPrefix, JSONUtils.toJSON(payDto));
        // 发起支付
        JDSaleByContractRequest jdSaleByContractRequest = new JDSaleByContractRequest();
        jdSaleByContractRequest.setMerchantNo(payDto.getMap().get("merchantNo").toString());
        jdSaleByContractRequest.setContractNo(payDto.getMap().get("contractNo").toString());
        jdSaleByContractRequest.setOutTradeNo(payDto.getPayNo());
        jdSaleByContractRequest.setTradeAmount(String.valueOf(payDto.getAmount()));
        JDSaleByContractResponse jdSaleByContractResponse;
        try {
            jdSaleByContractResponse = jdAdpaterService.saleByContractNo(logPrefix, jdSaleByContractRequest);
        } catch (PaymentException ep) {
            log.error("{} JDAdapter#pay_error payDto={} error : {}", logPrefix, JSON.toJSONString(payDto), ep);
            throw ep;
        } catch (Exception e) {
            log.error("{} JDAdapter#pay error : {}", logPrefix, e);
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR.getCode(), ResultCodeEnum.CHANNEL_CONNECT_ERROR.getMsg());
        }
        // 返回数据
        PayBo payBo = new PayBo();
        JSONObject payLoad = new JSONObject();
        payBo.setPayNO(payDto.getPayNo());
        payLoad.put("tradeNo", jdSaleByContractResponse.getTradeNo());
        payLoad.put("payNo", payDto.getPayNo());
        payBo.setPayLoad(payLoad.toJSONString());
        return payBo;
    }

    /**
     * 订单关闭：京东支付无订单关闭接口
     */
    @Override
    public OrderClosedBo orderClosed(OrderClosedDto orderClosedDto) throws PaymentException {
        log.info("JDAdapter#orderClosed orderClosedDto={}", JSONUtils.toJSON(orderClosedDto));
        throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR);
    }

    /**
     * 退款
     */
    @Override
    public RefundBO refund(RefundDto refundDto) throws PaymentException {
        String logPrefix = "jdCardRefund " + refundDto.getPayNo();
        log.info("{} JDAdapter#refund refundDto={}", logPrefix, JSONUtils.toJSON(refundDto));
        String merchantNo;
        try {
            merchantNo = JDConstants.cardMerchant(logPrefix, refundDto.getBusinessType());
        } catch (Exception e) {
            JSONObject extra = JSONObject.parseObject(refundDto.getExtra());
            merchantNo = extra.getString("merchantNo");
        }
        // 发起退款
        JDTradeRefundRequestVo jdTradeRefundRequestVo = new JDTradeRefundRequestVo();
        jdTradeRefundRequestVo.setOutTradeNo(refundDto.getRefundNo());
        jdTradeRefundRequestVo.setOrignalOutTradeNo(refundDto.getPayNo());
        jdTradeRefundRequestVo.setMerchantNo(merchantNo);
        jdTradeRefundRequestVo.setRefundAmount(String.valueOf(refundDto.getAmount()));
        JDTradeRefundResponseVo tradeRefundResponseVo;
        try {
            tradeRefundResponseVo = jdAdpaterService.tradeRefund(logPrefix, jdTradeRefundRequestVo);
        } catch (PaymentException ep) {
            log.error("{} JDAdapter#refund request:{} ", logPrefix, JSON.toJSONString(refundDto), ep);
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR, ep.getErrMsg());
        } catch (Exception e) {
            log.error("{} JDAdapter#refund request:{} ", logPrefix, JSON.toJSONString(refundDto), e);
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR, e.getMessage());
        }
        // 返回数据
        RefundBO refundBo = new RefundBO();
        refundBo.setRefundNo(refundDto.getRefundNo());
        refundBo.setChannelRefundNo(tradeRefundResponseVo.getTradeNo());
        refundBo.setChannelTransactionNo(tradeRefundResponseVo.getOrignalTradeNo());
        refundBo.setStatus(RefundOrder.STATUS_IN);
        return refundBo;
    }

    /**
     * 检查交易状态
     */
    @Override
    public TransactionResultBO queryTransaction(TransactionParam param) throws PaymentException {
        String logPrefix = "jdCardqueryTransaction " + param.getTradeNo();
        log.info("{} queryTransaction：{} ", logPrefix, JSON.toJSONString(param));
        QueryTransactionStatusDto queryTransactionStatusDto = QueryTransactionStatusDto.build(param.getBusinessType(), param.getBusinessOrderType(), param.getTradeNo(), QueryTransactionStatusDto.TRADE_TYPE_PAY, null, null, param.getTradeNo(),param.getPayChannel());
        QueryResultBo resultBo = queryTransactionStatus(queryTransactionStatusDto);
        TransactionResultBO queryResultBo = new TransactionResultBO();
        queryResultBo.setTradeNo(param.getTradeNo());
        queryResultBo.setStatus(resultBo.getStatus());
        queryResultBo.setSuccessTime(resultBo.getSuccessTime());
        queryResultBo.setChannelChargeNo(resultBo.getChannelChargeNo());
        queryResultBo.setBankChargeNo(resultBo.getChannelChargeNo());
        queryResultBo.setAmount(resultBo.getAmount());
        queryResultBo.setChannel(param.getChannel());
        queryResultBo.setMerchantId(resultBo.getMerchantId());
        return queryResultBo;
    }
        /**
         * 检查交易状态
         */
    @Override
    public QueryResultBo queryTransactionStatus(QueryTransactionStatusDto queryTransactionStatusDto) throws PaymentException {
        String logPrefix = "jdCardQuery " + queryTransactionStatusDto.getPayNo();
        log.info("{} JDAdapter#queryTransactionInfo 入参信息：{} ", logPrefix, JSON.toJSONString(queryTransactionStatusDto));
        String merchantNo;
        try {
            merchantNo = JDConstants.cardMerchant(logPrefix, queryTransactionStatusDto.getBusinessType());
        } catch (Exception e) {
            // 查询预支付订单
            PrePayOrder prePayOrderByPayNo = prePayOrderService.getPrePayOrderByPayNo(queryTransactionStatusDto.getPayNo());
            JSONObject extra = JSONObject.parseObject(prePayOrderByPayNo.getExtra());
            merchantNo = extra.getString("merchantNo");
        }
        // 查询交易状态
        JDTradeQueryRequestVo jdTradeQueryRequestVo = new JDTradeQueryRequestVo();
        jdTradeQueryRequestVo.setMerchantNo(merchantNo);
        jdTradeQueryRequestVo.setOutTradeNo(queryTransactionStatusDto.getTransactionNo());
        JDTradeQueryResponseVo jdTradeQueryResponseVo;
        try {
            jdTradeQueryResponseVo = jdAdpaterService.tradeQuery(logPrefix, jdTradeQueryRequestVo);
        } catch (PaymentException ep) {
            if ("00072".equals(ep.getErrCode())) {
                log.info("{} 订单不存在，返回null，{}", logPrefix, JSON.toJSONString(queryTransactionStatusDto));
                return null;
            }
            log.error("{} JDAdapter#queryTransactionInfo error separateAccountDO:", logPrefix, JSON.toJSONString(queryTransactionStatusDto), ep);
            throw ep;
        } catch (Exception e) {
            log.error("{} JDAdapter#queryTransactionInfo error separateAccountDO:", logPrefix, JSON.toJSONString(queryTransactionStatusDto), e);
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR);
        }
        QueryResultBo queryResultBo = new QueryResultBo();
        queryResultBo.setMerchantId(merchantNo);
        if (jdTradeQueryResponseVo.getTradeStatus().equals(JDPayTradeStatusEnum.FINI.getCode()) || jdTradeQueryResponseVo.getTradeStatus().equals(JDPayTradeStatusEnum.REFU.getCode())) {
            queryResultBo.setStatus(QueryResultBo.FINISHED);
            queryResultBo.setSuccessTime(Long.valueOf(jdTradeQueryResponseVo.getFinishDate()) / 1000);
            queryResultBo.setChannelChargeNo(jdTradeQueryResponseVo.getTradeNo());
            queryResultBo.setAmount(jdTradeQueryResponseVo.getTradeAmount());
        } else if (jdTradeQueryResponseVo.getTradeStatus().equals(JDPayTradeStatusEnum.CLOS.getCode())) {
            queryResultBo.setStatus(QueryResultBo.FAILED);
            queryResultBo.setFailureCode(jdTradeQueryResponseVo.getResultCode());
            queryResultBo.setFailureMsg(jdTradeQueryResponseVo.getResultDesc());
        } else {
            queryResultBo.setStatus(QueryResultBo.PROCESSING);
        }
        return queryResultBo;
    }

    /**
     * 查询退款状态
     */
    @Override
    public QueryResultBo queryRefundStatus(RefundOrder refundOrder) throws PaymentException {
        PayResultOrder resultOrder = payResultOrderService.selectByPayNoAndChannel(refundOrder.getPayNo(), refundOrder.getChannel());
        QueryTransactionStatusDto queryTransactionStatusDto = QueryTransactionStatusDto.build(resultOrder.getBusinessType(), resultOrder.getBusinessOrderType(), refundOrder.getRefundNo(), QueryTransactionStatusDto.TRADE_TYPE_REFUND, getPayeeAccountId(refundOrder.getUserId()), refundOrder.getUpdateTime(), refundOrder.getPayNo(),resultOrder.getPayChannel());
        return queryTransactionStatus(queryTransactionStatusDto);
    }

    /**
     * 查询支付状态
     */
    @Override
    public QueryResultBo queryPayStatus(String tradeNo, PrePayOrder prePayOrder, String payMode) throws PaymentException {
        Object channelObj = JSONUtils.getValueFromJson(prePayOrder.getExtra(), "channel");
        String channel = channelObj == null ? "": (String) channelObj;
        QueryTransactionStatusDto queryTransactionStatusDto = QueryTransactionStatusDto.build(prePayOrder.getBusinessType(), prePayOrder.getBusinessOrderType(), prePayOrder.getPayNo(), QueryTransactionStatusDto.TRADE_TYPE_PAY, prePayOrder.getReceiverId(), prePayOrder.getCreateTime(), prePayOrder.getPayNo(),channel);
        return queryTransactionStatus(queryTransactionStatusDto);
    }

    /**
     * 获取收款人信息
     */
    private String getPayeeAccountId(String accountId) {
        if (StringUtils.isBlank(accountId)) {
            return accountId;
        }
        return isBigShop(accountId) ? ApolloUtil.getProperty(Constants.EC_POP_BIG_SHOP_PINGAN_ACCOUNT_ID) : accountId;
    }

    /**
     * 判断是否为大商户
     */
    private boolean isBigShop(String accountId) {
        return Objects.equals(ApolloUtil.getProperty(Constants.POP_DIRECT_PAY_YBM_TECH_USER_ID), accountId) || Objects.equals(ApolloUtil.getProperty(Constants.EC_POP_BIG_SHOP_PINGAN_ACCOUNT_ID), accountId);
    }

}
